package com.zlx.mall.basic.web.aspect;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.jwt.JWT;
import com.zlx.mall.basic.annotations.ValidateToken;
import com.zlx.mall.basic.common.constant.RedisKeyConstant;
import com.zlx.mall.basic.common.exception.BaseResponseStatusEnum;
import com.zlx.mall.basic.common.exception.BizRuntimeException;
import com.zlx.mall.basic.common.model.SystemParam;
import com.zlx.mall.basic.util.JwtUtils;
import com.zlx.mall.basic.web.holder.IdContextHolder;
import com.zlx.mall.basic.web.model.BaseRequest;
import com.zlx.mall.biz.access.holder.UserContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Objects;

/**
 * @Author xiatian
 * @Date 2024/5/28 星期二 15:46
 * @注释
 */
@Order(2)
@Component
@Aspect
@Slf4j
public class ValidateTokenAop {
    @Autowired
    RedisTemplate redisTemplate;

    @Pointcut(value = "(@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.PostMapping)) " +
            "||@annotation(org.springframework.web.bind.annotation.GetMapping)")
    private void pointcut() {
    }

    @Before("pointcut()")
    public void doBefore(JoinPoint joinPoint) {
        // 判断是否校验token
        ValidateToken annotation = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(ValidateToken.class);
        try {
            SystemParam systemParam = UserContextHolder.getSystemParam();

            if (Objects.isNull(systemParam) || !StringUtils.hasText(systemParam.getToken())) {
                throw new IllegalStateException("系统参数缺失");
            }

            String token = systemParam.getToken();

            JWT jwt = JwtUtils.parse(token);

            if (!jwt.validate(0)) {
                throw new IllegalStateException("JWT校验失败");
            }

            JSONObject payloads = jwt.getPayloads();

            Long userId = payloads.getLong(JwtUtils.PAYLOAD_USER_ID);
            String mobile = payloads.getStr(JwtUtils.PAYLOAD_MOBILE);

            String key = RedisKeyConstant.CACHE_KEY_USER_TOKEN + mobile;
            String redisToken = (String) redisTemplate.opsForValue().get(key);
            if (!StringUtils.hasText(redisToken)) {
                throw new IllegalStateException("无缓存Token");
            }

            // 缓存存在
            String subToken = StrUtil.subBetween(token, ".", ".");
            if (!redisToken.equals(subToken)) {
                throw new IllegalStateException("与缓存中的Token不一致");
            }

            for (Object arg : joinPoint.getArgs()) {
                if (arg instanceof BaseRequest) {
                    ((BaseRequest) arg).setUserId(userId);
                    break;
                }
            }

            UserContextHolder.setUserId(userId);
            IdContextHolder.setId(userId);

        } catch (Exception e) {
            if (annotation != null && annotation.validate()) {
                throw new BizRuntimeException(BaseResponseStatusEnum.INVALID_LOGIN_STATUS, e);
            }
        }

    }


}
